package com.ai.bitcoin.redis.service.impl;

import com.ai.bitcoin.constant.Bcc;
import com.ai.bitcoin.constant.CacheConstant;
import com.ai.bitcoin.constant.CommonConstant;
import com.ai.bitcoin.jpa.entity.BccAnnoInfoCrawl;
import com.ai.bitcoin.jpa.entity.BccNews;
import com.ai.bitcoin.jpa.service.BccBatchService;
import com.ai.bitcoin.jpa.service.BccNewsService;
import com.ai.bitcoin.jpa.service.BccRankService;
import com.ai.bitcoin.jpa.service.BccScoreRuleService;
import com.ai.bitcoin.redis.service.BccRedisService;
import com.ai.bitcoin.util.DateUtil;
import com.ai.bitcoin.vo.HtmlReportGenerateVO;
import com.ai.bitcoin.vo.Price2BccVo;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class BccRedisServiceImpl implements BccRedisService {
    @Value("${redisCacheHour}")
    long redisCacheHour;
    @Autowired
    @Qualifier(value = "stringRedisTemplate")
    private RedisTemplate<String, String> stringRedisTemplate;

    @Autowired
    private RedisTemplate redisTemplate;


    @Autowired
    BccScoreRuleService bccScoreRuleService;
    @Autowired
    BccRankService bccRankService;
    @Autowired
    BccBatchService bccBatchService;
    @Autowired
    BccNewsService bccNewsService;

    static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");


    @Override
    public void updateVersion(String cacheType, String newVersion) {
        String key = getKey(cacheType, "version");
        stringRedisTemplate.opsForValue().set(key, newVersion);
    }

    @Override
    public String getCurrentVersion(String type) {
        String key = getKey(type, "version");
        String version = stringRedisTemplate.opsForValue().get(key);
        if (StringUtils.isEmpty(version)) {
            stringRedisTemplate.opsForValue().set(key, "version1");
        }
        return version;
    }

    @Override
    public String getNextVersion(String type) {
        String key = getKey(type, "version");
        String currVersion = stringRedisTemplate.opsForValue().get(key);
        String nextVersion;
        if (StringUtils.equals(currVersion, "version1")) {
            nextVersion = "version2";
        } else {
            nextVersion = "version1";
        }
        return nextVersion;
    }

    @Override
    public void cacheTop2Redis(String version, JSONObject value) {
        String key = getKey(Bcc.Cache.Top, version);
        stringRedisTemplate.opsForValue().set(key, value.toString());
    }


    @Override
    public void cacheRank2Redis(String rankType, String bccId, String version, JSONObject value) {
        String key = getKey(Bcc.Cache.RANK, rankType, bccId, version);
        stringRedisTemplate.opsForValue().set(key, value.toString());
    }

    @Override
    public void cacheDetail2Redis(String bccId, String version, JSONObject value) {
        String key = getKey(Bcc.Cache.RANK, Bcc.RankType.RANK_VALUE_TODAY_DETAIL, bccId, version);
        stringRedisTemplate.opsForValue().set(key, value.toString());
    }

    @Override
    public String getRank(String rankType, String bccId) {
        String key = getKey(Bcc.Cache.RANK, rankType, bccId, getCurrentVersion(Bcc.Cache.Version.CALCULATE));
        return stringRedisTemplate.opsForValue().get(key);
    }

    @Override
    public void cacheRankPage(String rankType, int pageSize, int pageNum, String version, JSONArray show) {
        String key = getKey(Bcc.Cache.HomePage.RANK_PAGE, rankType, pageSize + "", pageNum + "", version);
        stringRedisTemplate.opsForValue().set(key, show.toString());

    }

    @Override
    public String getRankPage(String rankType, int pageSize, int pageNum) {
        String key = getRankKey(rankType, pageSize, pageNum);
        return stringRedisTemplate.opsForValue().get(key);
    }

    @Override
    public String getRankKey(String rankType, int pageSize, int pageNum) {
        String version = getCurrentVersion(Bcc.Cache.Version.CALCULATE);
        return getKey(Bcc.Cache.HomePage.RANK_PAGE, rankType, pageSize + "", pageNum + "", version);
    }

    @Override
    public void cacheHomePageNum2Redis(String type, String nextVersion, int pageSize) {
        String key = getKey(Bcc.Cache.HomePage.PAGE_NUM, type, nextVersion);
        stringRedisTemplate.opsForValue().set(key, pageSize + "");
    }

    @Override
    public void cacheBccCount2Redis(String type, String nextVersion, long total) {
        String key = getKey(Bcc.Cache.HomePage.TOTAL, type, nextVersion);
        stringRedisTemplate.opsForValue().set(key, total + "");
    }

    @Override
    public String getBccCount(String type) {
        String version = getCurrentVersion(Bcc.Cache.Version.CALCULATE);
        String key = getKey(Bcc.Cache.HomePage.TOTAL, type, version);
        return stringRedisTemplate.opsForValue().get(key);
    }

    @Override
    public void cacheCurrentPrice2Redis(String bccId, JSONObject value) {
        String key = getKey(Bcc.Cache.Price.CURRENT_PRICE, bccId);
        stringRedisTemplate.opsForValue().set(key, value.toString());
    }

    @Override
    public void cache24hPrice2Redis(String bccId, JSONObject price) {
        String h24 = get24hPrice(bccId);
        String key = getKey(Bcc.Cache.Price.H24_PRICE, bccId);
        if (StringUtils.isEmpty(h24)) {
            JSONArray jsonArray = new JSONArray();
            jsonArray.add(price);
            stringRedisTemplate.opsForValue().set(key, jsonArray.toString());
        } else {
            JSONArray jsonArray = JSONArray.fromObject(h24);
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject node = JSONArray.fromObject(h24).getJSONObject(i);
                Iterator<JSONObject> it = jsonArray.iterator();
                while (it.hasNext()) {
                    JSONObject item = it.next();
                    String time = node.optString("priceTimestamp");
                    try {
                        Date oldTime = simpleDateFormat.parse(time);
                        Calendar calendar = Calendar.getInstance();
                        calendar.add(Calendar.DAY_OF_WEEK, -1);
                        if (oldTime.after(calendar.getTime())) {
                            break;
                        } else {
                            it.remove();
                        }
                    } catch (ParseException e) {
                        log.info("室间格式错误:{}", time);
                        it.remove();
                    }
                }
            }
            jsonArray.add(price);
            stringRedisTemplate.opsForValue().set(key, jsonArray.toString());
        }
    }

    @Override
    public void cover24hPrice2Redis(String bccId, JSONArray jsonArray) {
        String key = getKey(Bcc.Cache.Price.H24_PRICE, bccId);
        stringRedisTemplate.opsForValue().set(key, jsonArray.toString());
    }

    @Override
    public void coverTodayPrice2Redis(String bccId, JSONArray value) {
        String key = getKey(Bcc.Cache.Price.TODAY_PRICE, bccId);
        stringRedisTemplate.opsForValue().set(key, value.toString());
    }

    @Override
    public String get24hPrice(String bccId) {
        String key = getKey(Bcc.Cache.Price.H24_PRICE, bccId);
        return stringRedisTemplate.opsForValue().get(key);
    }

    @Override
    public String getCurrentPrice(String bccId) {
        String key = getKey(Bcc.Cache.Price.CURRENT_PRICE, bccId);
        return stringRedisTemplate.opsForValue().get(key);
    }

    @Override
    public String getHomePageNum(String rankType) {
        String version = getCurrentVersion(Bcc.Cache.Version.CALCULATE);
        String key = getKey(Bcc.Cache.HomePage.PAGE_NUM, rankType, version);
        return stringRedisTemplate.opsForValue().get(key);
    }


    @Override
    public String getDayPrice(String bccId) {
        String key = getKey(Bcc.Cache.Price.DAY_PRICE, bccId);
        return stringRedisTemplate.opsForValue().get(key);
    }

    @Override
    public void cacheDayPrice(String bccId, JSONObject node) {
        String key = getKey(Bcc.Cache.Price.DAY_PRICE, bccId);
        String value = stringRedisTemplate.opsForValue().get(key);
        JSONArray jsonArray;
        if (StringUtils.isEmpty(value)) {
            jsonArray = new JSONArray();
        } else {
            jsonArray = JSONArray.fromObject(value);
        }
        jsonArray.add(node);
        stringRedisTemplate.opsForValue().set(key, jsonArray.toString());
    }

    @Override
    public void addDayPriceNode(String bccId, JSONObject node) {
        String key = getKey(Bcc.Cache.Price.DAY_PRICE, bccId);
        String nodes = stringRedisTemplate.opsForValue().get(key);
        JSONArray jsonArray;
        if (StringUtils.isNotEmpty(nodes)) {
            jsonArray = JSONArray.fromObject(nodes);
        } else {
            jsonArray = new JSONArray();
        }
        if (node.size() > 0)
            jsonArray.add(node);
        stringRedisTemplate.opsForValue().set(key, jsonArray.toString());
    }

    @Override
    public void addDayPriceNodeList(String bccId, JSONArray nodeList) {
        String key = getKey(Bcc.Cache.Price.DAY_PRICE, bccId);
        if (dayUpdate(Bcc.Cache.Time.TODAY_PRICE)) {
            stringRedisTemplate.delete(key);
        }
        String nodes = stringRedisTemplate.opsForValue().get(key);
        JSONArray jsonArray;
        if (StringUtils.isNotEmpty(nodes)) {
            jsonArray = JSONArray.fromObject(nodes);
        } else {
            jsonArray = new JSONArray();
        }
        jsonArray.addAll(nodeList);
        stringRedisTemplate.opsForValue().set(key, jsonArray.toString());
    }

    @Override
    public void deleteDayPrice(String bccId) {
        String key = getKey(Bcc.Cache.Price.DAY_PRICE, bccId);
        stringRedisTemplate.delete(key);
    }

    @Override
    public String getTodayPrice(String bccId) {
        String key = getKey(Bcc.Cache.Price.TODAY_PRICE, bccId);
        if (dayUpdate(Bcc.Cache.Time.TODAY_PRICE)) {
            stringRedisTemplate.delete(key);
        }
        return stringRedisTemplate.opsForValue().get(key);
    }

    @Override
    public void addTodayPriceNode(String bccId, JSONObject node) {
        String key = getKey(Bcc.Cache.Price.TODAY_PRICE, bccId);
        if (dayUpdate(Bcc.Cache.Time.TODAY_PRICE)) {
            stringRedisTemplate.delete(key);
        }
        String nodes = stringRedisTemplate.opsForValue().get(key);
        JSONArray jsonArray;
        if (StringUtils.isNotEmpty(nodes)) {
            jsonArray = JSONArray.fromObject(nodes);
            for (int i = 0; i < jsonArray.size(); i++) {
                Iterator<JSONObject> it = jsonArray.iterator();
                while (it.hasNext()) {
                    JSONObject item = it.next();
                    String time = item.optString("priceTimestamp");
                    try {
                        Date priceTime = simpleDateFormat.parse(time);
                        Calendar yesterday = Calendar.getInstance();
                        yesterday.set(Calendar.HOUR_OF_DAY, 0);
                        yesterday.set(Calendar.MINUTE, 0);
                        yesterday.set(Calendar.SECOND, 0);
                        if (priceTime.after(yesterday.getTime())) {
                            break;
                        } else {
                            it.remove();
                        }
                    } catch (ParseException e) {
                        log.info("室间格式错误:{}", time);
                        it.remove();
                    }
                }
            }
        } else {
            jsonArray = new JSONArray();
        }
        if (node.size() > 0)
            jsonArray.add(node);
        stringRedisTemplate.opsForValue().set(key, jsonArray.toString());
    }

    @Override
    public void addTodayPriceNodeList(String bccId, JSONArray nodeList) {
        String key = getKey(Bcc.Cache.Price.TODAY_PRICE, bccId);
        String nodes = stringRedisTemplate.opsForValue().get(key);
        JSONArray jsonArray;
        if (StringUtils.isNotEmpty(nodes)) {
            jsonArray = JSONArray.fromObject(nodes);
        } else {
            jsonArray = new JSONArray();
        }
        jsonArray.addAll(nodeList);
        stringRedisTemplate.opsForValue().set(key, jsonArray.toString());
    }

    @Override
    public String getTop() {
        String key = getKey(Bcc.Cache.Top, getCurrentVersion(Bcc.Cache.Version.CALCULATE));
        return stringRedisTemplate.opsForValue().get(key);
    }

    public String getKey(String... args) {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < args.length; i++) {
            stringBuilder.append(Bcc.SEPARATOR + args[i]);
        }
        return stringBuilder.toString().substring(1);
    }

    @Override
    public String getTime(String type) {
        String key = getKey(Bcc.Time, type);
        return stringRedisTemplate.opsForValue().get(key);
    }

    @Override
    public void setTime(String type, String time) {
        String key = getKey(Bcc.Time, type);
        stringRedisTemplate.opsForValue().set(key, time);
    }

    @Override
    public boolean dayUpdate(String type) {
        boolean update = true;
        String time = getTime(type);
        if (StringUtils.isNotEmpty(time)) {
            try {
                Date insertTime = simpleDateFormat.parse(time);
                Calendar day = Calendar.getInstance();
                day.set(Calendar.HOUR_OF_DAY, 0);
                day.set(Calendar.MINUTE, 0);
                day.set(Calendar.SECOND, 0);
                if (insertTime.before(day.getTime())) {
                    update = true;
                } else {
                    update = false;
                }
            } catch (ParseException e) {
                update = true;
            }
        } else {
            update = true;
        }
        if (update) {
            setTime(type, simpleDateFormat.format(new Date()));
        }
        return update;
    }

    @Override
    public void cacheBasic2Redis(String bccId, JSONObject value) {
        String key = getKey(Bcc.Cache.BASIC_INFO, bccId);
        stringRedisTemplate.opsForValue().set(key, value.toString());
    }

    @Override
    public void cacheBccList2Redis(JSONArray list) {
        String nextVersion = getNextVersion(Bcc.Cache.BCC_LIST);
        String key = getKey(Bcc.Cache.BCC_LIST, nextVersion);
        stringRedisTemplate.opsForValue().set(key, list.toString());
        updateVersion(Bcc.Cache.BCC_LIST, nextVersion);
    }

    @Override
    public String getBccList() {
        String version = getCurrentVersion(Bcc.Cache.BCC_LIST);
        String key = getKey(Bcc.Cache.BCC_LIST, version);
        return stringRedisTemplate.opsForValue().get(key);
    }

    @Override
    public String getBasicInfo(String bccId) {
        String key = getKey(Bcc.Cache.BASIC_INFO, bccId);
        return stringRedisTemplate.opsForValue().get(key);
    }

    @Override
    public void put(String key, String value) {
        stringRedisTemplate.opsForValue().set(key, value);
    }

    @Override
    public String get(String key) {
        return stringRedisTemplate.opsForValue().get(key);
    }

    @Override
    public void cacheReportDetail2Redis(String bccId, JSONObject value) {
        String key = getKey(Bcc.Cache.REPORT_BASIC_INFO, bccId);
        stringRedisTemplate.opsForValue().set(key, value.toString());
    }

    @Override
    public String getReportDetail(String bccId) {
        String key = getKey(Bcc.Cache.REPORT_BASIC_INFO, bccId);
        return stringRedisTemplate.opsForValue().get(key);
    }

    @Override
    public JSONObject getReport(String bccId) {
        String rank = getRank(Bcc.RankType.RANK_VALUE_TODAY_DETAIL, bccId);
        String h24Price = get24hPrice(bccId);
        String reportDetail = getReportDetail(bccId);
        String currentPrice = getCurrentPrice(bccId);
        String basicInfo = getBasicInfo(bccId);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("basicInfo", reportDetail);
        jsonObject.put("h24Price", h24Price);
        jsonObject.put("rank", rank);
        jsonObject.put("currentPrice", currentPrice);
        jsonObject.put("basicRealInfo", basicInfo);

        String digestNews = getDigestNews();
        jsonObject.put("digestNews", digestNews);
        return jsonObject;
    }


    @Override
    public void cacheDigestNews(JSONArray jsonArray) {
        String key = getKey(Bcc.Cache.NEWS_DIGEST_INFO);
        stringRedisTemplate.opsForValue().set(key, jsonArray.toString());
    }

    @Override
    public String getDigestNews() {
        String key = getKey(Bcc.Cache.NEWS_DIGEST_INFO);
        return stringRedisTemplate.opsForValue().get(key);
    }

    @Override
    public void cacheNews(String id, JSONObject jsonObject) {
        String key = getKey(Bcc.Cache.NEWS_INFO, id);
        stringRedisTemplate.opsForValue().set(key, jsonObject.toString());
    }

    @Override
    public String getNews(String id) {
        String key = getKey(Bcc.Cache.NEWS_INFO, id);
        return stringRedisTemplate.opsForValue().get(key);
    }

    @Override
    public void cache2BitCoinReport(String bccId, HtmlReportGenerateVO reportGenerateVO) {
        String key = CacheConstant.REPORT + DateUtil.currentDate2Str(CommonConstant.REPORT_HTML_PREFIX_PATH) + "_" + bccId;
        String jsonString = com.alibaba.fastjson.JSONObject.toJSONString(reportGenerateVO);
        log.info("【币的报告放入缓存】 key:{}",key);
        stringRedisTemplate.opsForValue().set(key, jsonString);
    }

    @Override
    public HtmlReportGenerateVO getBitCoinReport(String key) {
        String jsonString = stringRedisTemplate.opsForValue().get(key);
        return com.alibaba.fastjson.JSONObject.parseObject(jsonString, HtmlReportGenerateVO.class);
    }

    public void cache2BitCoinBccNews(String bccId, List<BccNews> bccNewsList) {
        String key =CacheConstant.BITCOIN_BCC_NEWS +  DateUtil.currentDate2Str(CommonConstant.REPORT_HTML_PREFIX_PATH) + "_" + bccId;
        String jsonString = com.alibaba.fastjson.JSONObject.toJSONString(bccNewsList);
        stringRedisTemplate.opsForValue().set(key, jsonString);
    }

    public List<BccNews> getBitCoinBccNews(String key) {
        String jsonString = stringRedisTemplate.opsForValue().get(key);
        return com.alibaba.fastjson.JSONArray.parseArray(jsonString, BccNews.class);
    }

    public void cache2SingleBccNew(String bccId, String newsId, BccNews bccNewsList) {
        String key = CacheConstant.SINGLE_BCC_NEWS + bccId + "_" + newsId;
        String jsonString = com.alibaba.fastjson.JSONObject.toJSONString(bccNewsList);
        stringRedisTemplate.opsForValue().set(key, jsonString,3,TimeUnit.DAYS);
    }


    public BccNews getSingleBccNew(String key) {
        String jsonString = stringRedisTemplate.opsForValue().get(key);
        return com.alibaba.fastjson.JSONObject.parseObject(jsonString,BccNews.class);
    }

    public void cache2SingleBccAnnoInfo(String bccId, String annoId, BccAnnoInfoCrawl infoCrawl) {
        String key = CacheConstant.SINGLE_ANNO_INFO + bccId + "_" + annoId;
        String jsonString = com.alibaba.fastjson.JSONObject.toJSONString(infoCrawl);
        stringRedisTemplate.opsForValue().set(key, jsonString,3,TimeUnit.DAYS);
    }

    public BccAnnoInfoCrawl getSingleBccAnnoInfo(String key) {
        String jsonString = stringRedisTemplate.opsForValue().get(key);
        return com.alibaba.fastjson.JSONObject.parseObject(jsonString,BccAnnoInfoCrawl.class);
    }

    public void cache2SinglePrice2BccVo(String bccId, Price2BccVo price2BccVo) {
        String key = CacheConstant.SINGLE_PRICE_INFO + bccId;
        String jsonString = com.alibaba.fastjson.JSONObject.toJSONString(price2BccVo);
        stringRedisTemplate.opsForValue().set(key, jsonString,3,TimeUnit.DAYS);
    }

    public Price2BccVo getSinglePrice2BccVo(String key) {
        String jsonString = stringRedisTemplate.opsForValue().get(key);
        return com.alibaba.fastjson.JSONObject.parseObject(jsonString,Price2BccVo.class);
    }
}
